/*
 * DIM-SUM操作系统 - 处理器相关
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <dim-sum/bug.h>
#include <dim-sum/linkage.h>
#include <dim-sum/sched.h>
#include <dim-sum/stringify.h>
#include <dim-sum/process.h>
#include <dim-sum/errno.h>
#include <dim-sum/boot_allotter.h>
#include <dim-sum/beehive.h>
#include <dim-sum/mmu.h>
#include <dim-sum/exec.h>
#include <uapi/asm/ptrace.h>
#include <asm/asm-offsets.h>
#include <asm/head64.h>
#include <asm/sysreg.h>
#include <asm/processor.h>
#include <asm/exception.h>
#include <asm/tlbflush.h>


static inline void inv_all_tlb(void)
{
	flush_tlb_all();
}

/**
 * 默认的idle节能调用:WFI
 */
void cpu_do_idle(void)
{
	mb();
	asm volatile(
		"wfi \n\t"
	);
	return;
}

void fork_ret_before(struct exception_spot* s)
{
	rq_unlock();
	local_irq_enable();
	preempt_enable();
}


/**
 * 线程切换时，保存线程的寄存器并恢复新线程的寄存器
 */
struct task_desc* __switch_cpu_context(struct task_desc *prev,
	struct task_desc *next)
{
	// pr_info("%s %d %s %s\n", __FUNCTION__, __LINE__, prev->name, next->name);
	__switch_cpu_asm(prev, next, next->stack);
	return prev;
}

/**
 * 切换进程的fpsimd上下文
 */
asmlinkage void __switch_fpsimd_context(struct task_desc *prev,
	struct task_desc *next)
{
	save_fp_regs(prev);
	restore_fp_regs(next);
}

/**
 * 切换进程的MMU页表上下文
 */
asmlinkage void __switch_mmu_context(struct process_desc *prev,
	struct process_desc *new)
{	
	/**
	 * 注意并不是每个进程都有mem_desc结构
	 * 比如init_idle_process函数建立的进程
	 */
	if (!new || !new->mem)
		return;
	
	mmu_set_tlb(&new->mem->mem_arch.mmu);
	return;
}


void start_user_task(struct task_desc *task)
{
	ASSERT(task);
	ASSERT(task->user_regs);
	start_user_run((u64)task->user_regs);
}

void init_user_context(struct exception_spot* s)
{
	struct task_desc *task = current;
	if (!task || !task->user_regs)
		BUG();

	BUG_ON(s != task->user_regs);
	memset(s, 0, sizeof(*s));
	if (task->user_exec_info && 
			task->user_exec_info->user_argenv_sp) {
		/**
		 * 有命令行参数和环境变量的情况
		 */
		s->sp = (u64)(task->user_exec_info->user_argenv_sp);

	} else {
		/**
		 * 没有有命令行参数和环境变量或者处理参数失败的情况
		 */
		s->sp = (u64)(mem_stack_top(current_mem) & PAGE_MASK);
	}
	s->sepc = (u64)task->task_main;
	/**
	 * 以后可能要配置RVV和浮点相关的特性
	 * SIE_bit0 0 
	 * SPIE_bit5 1 
	 * UBE_bit6 0
	 * SPP_bit8 0 
	 * VS_bit10_9 0 
	 * FS_bit14_13 0 
	 * XS_bit16_15 0 
	 * SUM_bit18 0 
	 * MXR_bit19 0 
	 * UXL_bit33_32 0
	 * SD_bit63 0
	 */
	s->sstatus = SR_PIE;
	/**
	 * 开启用户态浮点运算单元FPU
	 */
	s->sstatus |= SR_FS_INITIAL;
	return;
}

/**
 * 目前没有使用浮点寄存器
 */
void save_fp_regs(struct task_desc *task)
{
	__fstate_save_asm(task);
	return;
}

void restore_fp_regs(struct task_desc *task)
{
	__fstate_restore_asm(task);
	return;
}

void save_tls(struct task_desc *t)
{
}

void restore_tls(struct task_desc *t)
{
}

/**
 * 切换进程的tls上下文
 */
asmlinkage void __switch_tls_context(struct task_desc *prev,
	struct task_desc *next)
{
	save_tls(prev);
	restore_tls(next);
	return;	
}

void dump_task_user_regs(struct exception_spot* s)
{
	BUG();
	
	return;
}

int arch_destroy_task(struct task_desc *tsk)
{
	union process_union* p;
	void* addr;
	if (!tsk)
		return -EINVAL;
	BUG_ON(current == tsk);
	
	p = (union process_union*)tsk->stack;
	BUG_ON(!p);

	/* 释放MMU root页表 */
	addr = p->process_desc.arch_desc.arch_destroy.save_exitmmu_l1;
	if (addr)
		kfree(addr);
	return 0;
}

